﻿local _, ns = ...

local allshow = ns.ShowAuras

function BuffFramePoint(self)
	if self:IsForbidden() then return end
	--光环高度=高度*是否方形
	local aurahigth = PlateColorDB.auraSquare and PlateColorDB.auraScale or PlateColorDB.auraScale * 0.8
	
	--名字高度
	local namehight = PlateColorDB.enemyNameScale*1.4+2 or 0
	
	--BuffFrame默认高15,因为自定义了光环大小,要计算比原来偏移多少
	local auraY = PlateColorDB.auraSquare and PlateColorDB.auraScale-15 or PlateColorDB.auraScale*.8-15
	
	--是否显示名字
	local nameshown = self:GetParent().nametext and self:GetParent().nametext:IsShown()
	
	--设置当前目标显示个人资源时的偏移
	local isTarget = self:GetParent().unit and UnitIsUnit(self:GetParent().unit, "target");
	local targetYOffset = (GetCVarBool("nameplateResourceOnTarget") and isTarget) and 22 or 0;
	
	--手动设置的偏移
	local offsetY = PlateColorDB.auraOffsetY
	
	if (self:GetParent().unit and nameshown) then
		self:SetPoint("BOTTOMLEFT", self:GetParent().healthBar, "TOPLEFT", 0, 2 + auraY + namehight + targetYOffset + offsetY);
	else
		self:SetPoint("BOTTOMLEFT", self:GetParent().healthBar, "TOPLEFT", 0, 2 + auraY + targetYOffset + offsetY);
	end

	--个人资源光环缩放
	if self:GetParent().unit and UnitIsUnit(self:GetParent().unit,"player") then
		self:SetPoint("BOTTOMLEFT", self:GetParent().healthBar, "TOPLEFT", 0, 2 + auraY)
		self:SetScale(PlateColorDB.selfAuraScale)
		self:SetShown(PlateColorDB.selfHpAura)
	else
		self:SetScale(1)
	end
end

local function MyShowDebuff(self,aura,forceAll)
	local mydot = (aura.sourceUnit == "player" or aura.sourceUnit == "pet" or aura.sourceUnit == "vehicle")
	local showself = aura.nameplateShowPersonal and mydot
	local mytabledot = mydot and type(PlateColorDB["Auras"][aura.spellId]) == "table"
	local showall = aura.nameplateShowAll--self:ShouldShowBuff(aura, forceAll)
	local hideAll = type(PlateColorDB["Auras"][aura.spellId]) == "table" and PlateColorDB["Auras"][aura.spellId]["usehide"]
	if  (showself or mytabledot or showall or forceAll or allshow[aura.spellId]) and not hideAll then
		return true
	end
end
local function ParseAllAuras(self,forceAll)
	if self.auras == nil then
		self.auras = TableUtil.CreatePriorityTable(AuraUtil.DefaultAuraCompare, TableUtil.Constants.AssociativePriorityTable);
	else
		self.auras:Clear();
	end

	local function HandleAura(aura)
		if MyShowDebuff(self,aura,forceAll) then
			self.auras[aura.auraInstanceID] = aura;
		end
		return false;
	end

	local batchCount = nil;
	local usePackedAura = true;
	AuraUtil.ForEachAura(self.unit, self.filter, batchCount, HandleAura, usePackedAura);
end

local function PCUpdateBuffs(self,unit, unitAuraUpdateInfo, auraSettings)
if self:IsForbidden() then return end
	local filters = {};
	if auraSettings.helpful then
		table.insert(filters, AuraUtil.AuraFilters.Helpful);
	end
	if auraSettings.harmful then
		table.insert(filters, AuraUtil.AuraFilters.Harmful);
	end
	if auraSettings.raid then
		table.insert(filters, AuraUtil.AuraFilters.Raid);
	end
	if auraSettings.includeNameplateOnly then
		table.insert(filters, AuraUtil.AuraFilters.IncludeNameplateOnly);
	end
	local filterString = AuraUtil.CreateFilterString(unpack(filters));

	local previousFilter = self.filter;
	local previousUnit = self.unit;
	self.unit = unit;
	self.filter = filterString;

	local aurasChanged = false;
	if unitAuraUpdateInfo == nil or unitAuraUpdateInfo.isFullUpdate or unit ~= previousUnit or self.auras == nil or filterString ~= previousFilter then
		ParseAllAuras(self,auraSettings.showAll);
		aurasChanged = true;
	else
		if unitAuraUpdateInfo.addedAuras ~= nil then
			for _, aura in ipairs(unitAuraUpdateInfo.addedAuras) do
				if MyShowDebuff(self,aura,auraSettings.showAll) and not C_UnitAuras.IsAuraFilteredOutByInstanceID(unit, aura.auraInstanceID, filterString) then
					self.auras[aura.auraInstanceID] = aura;
					aurasChanged = true;
				end
			end
		end

		if unitAuraUpdateInfo.updatedAuraInstanceIDs ~= nil then
			for _, auraInstanceID in ipairs(unitAuraUpdateInfo.updatedAuraInstanceIDs) do
				if self.auras[auraInstanceID] ~= nil then
					local newAura = C_UnitAuras.GetAuraDataByAuraInstanceID(self.unit, auraInstanceID);
					self.auras[auraInstanceID] = newAura;
					aurasChanged = true;
				end
			end
		end

		if unitAuraUpdateInfo.removedAuraInstanceIDs ~= nil then
			for _, auraInstanceID in ipairs(unitAuraUpdateInfo.removedAuraInstanceIDs) do
				if self.auras[auraInstanceID] ~= nil then
					self.auras[auraInstanceID] = nil;
				end
			end
			aurasChanged = true;
		end
	end
	
	self:UpdateAnchor();

	if not aurasChanged then
		return;
	end

	self.buffPool:ReleaseAll();

	if auraSettings.hideAll or not self.isActive then
		return;
	end
	
	local buffIndex = 1;
	self.auras:Iterate(function(auraInstanceID, aura)
		local buff = self.buffPool:Acquire();
		
		if PlateColorDB.hideAura then self:Hide() return end
		
		buff.auraInstanceID = auraInstanceID;
		buff.isBuff = aura.isHelpful;
		buff.layoutIndex = buffIndex;
		buff.spellID = aura.spellId;
		
		local gaodu = PlateColorDB.auraSquare and PlateColorDB.auraScale or PlateColorDB.auraScale * 0.8
		buff.Icon:GetParent():SetSize(PlateColorDB.auraScale,gaodu)
		buff.Icon:SetSize(PlateColorDB.auraScale,gaodu)
		
		buff.Icon:SetTexCoord(0.1,0.9,0.1,0.9)
		buff.Cooldown:SetHideCountdownNumbers(not PlateColorDB.auraCooldownText)
		local textsize = PlateColorDB.auraScale * 0.65
		buff.Cooldown:GetRegions():SetFont(STANDARD_TEXT_FONT, textsize, "OUTLINE")
        buff:EnableMouse(PlateColorDB.auraToolTip)
		
		buff.Icon:SetTexture(aura.icon);
		if (aura.applications > 1) then
			buff.CountFrame.Count:SetText(aura.applications);
			buff.CountFrame.Count:Show();
		else
			buff.CountFrame.Count:Hide();
		end
		CooldownFrame_Set(buff.Cooldown, aura.expirationTime - aura.duration, aura.duration, aura.duration > 0, true);

		buff:Show();
		buffIndex = buffIndex + 1;
		return buffIndex >= BUFF_MAX_DISPLAY;

	end);

	--Add Cooldowns 
	if(auraSettings.showPersonalCooldowns and buffIndex < BUFF_MAX_DISPLAY and UnitIsUnit(unit, "player")) then 
		local nameplateSpells = C_SpellBook.GetTrackedNameplateCooldownSpells(); 
		for _, spellID in ipairs(nameplateSpells) do 
			if (not self:HasActiveBuff(spellID) and buffIndex < BUFF_MAX_DISPLAY) then
				local locStart, locDuration = C_Spell.GetSpellLossOfControlCooldown(spellID);
				local cooldownInfo = C_Spell.GetSpellCooldown(spellID);
				if ((locDuration and locDuration ~= 0) or (cooldownInfo and cooldownInfo.duration ~= 0)) then
					local spellInfo = C_Spell.GetSpellInfo(spellID);
					if(spellInfo) then 
						local buff = self.buffPool:Acquire();
						buff.isBuff = true;
						buff.layoutIndex = buffIndex;
						buff.spellID = spellID; 
						buff.auraInstanceID = nil;
						buff.Icon:SetTexture(spellInfo.iconID); 

						local chargeInfo = C_Spell.GetSpellCharges(spellID) or {};
						local charges, maxCharges = chargeInfo.currentCharges, chargeInfo.maxCharges;
						buff.Cooldown:SetSwipeColor(0, 0, 0);

						if (cooldownInfo and cooldownInfo.duration ~= 0) then
							CooldownFrame_Set(buff.Cooldown, cooldownInfo.startTime, cooldownInfo.duration, cooldownInfo.isEnabled, true, cooldownInfo.modRate);
						else
							CooldownFrame_Set(buff.Cooldown, locStart, locDuration, true, true);
						end

						if (maxCharges and maxCharges > 1) then
							buff.CountFrame.Count:SetText(charges);
							buff.CountFrame.Count:Show();
						else
							buff.CountFrame.Count:Hide();
						end
						buff:Show();
						buffIndex = buffIndex + 1;
					end
				end
			end
		end 
	end

	self:Layout();
end

local SetUpdateBuffs = CreateFrame("Frame")
SetUpdateBuffs:RegisterEvent("NAME_PLATE_UNIT_ADDED")
SetUpdateBuffs:SetScript("OnEvent", function(self, event,unit)
	local namePlate = C_NamePlate.GetNamePlateForUnit(unit,false)
	if not namePlate then return end
	if not namePlate.UnitFrame then return end
	if not namePlate.UnitFrame.BuffFrame then return end

	namePlate.UnitFrame.BuffFrame.UpdateAnchor = BuffFramePoint
	namePlate.UnitFrame.BuffFrame.UpdateBuffs = PCUpdateBuffs
end)


local function UpdateClassFrame(self)
	if self:IsForbidden() then return end
	if self.classNamePlateMechanicFrame then
		--如果你在副本内先点了友方,那么这些设置就无效了,因为会变成保护导致报错,重载后先选敌方就好
		if self.classNamePlateMechanicFrame:IsForbidden() then return end
		local bottomMostBar = nil;
		local namePlatePlayer = C_NamePlate.GetNamePlateForUnit("player", issecure());
		if namePlatePlayer then
			bottomMostBar = namePlatePlayer.UnitFrame.HealthBarsContainer;
		end
		--修改目标头上的职业资源位置,不然光环位置会出现偏移
		if GetCVarBool("nameplateResourceOnTarget") then
			local namePlateTarget = C_NamePlate.GetNamePlateForUnit("target", issecure());
			if namePlateTarget then
				self.classNamePlateMechanicFrame:SetParent(namePlateTarget);
				--计算我们的名字高度用于设置位置
				local namehight = PlateColorDB.enemyNameScale*1.4+3 or 0
				--设置目标身上的职业资源跟随全局缩放
				self.classNamePlateMechanicFrame:SetScale(GetCVar("nameplateGlobalScale"))
				self.classNamePlateMechanicFrame:ClearAllPoints();
				PixelUtil.SetPoint(self.classNamePlateMechanicFrame, "BOTTOM", namePlateTarget.UnitFrame.healthBar, "TOP", 0, namehight);
				self.classNamePlateMechanicFrame:Show();
			else
				--如果没在目标显示,需要把缩放设置回来
				self.classNamePlateMechanicFrame:Hide();
			end
		end
	end
end
hooksecurefunc(NamePlateDriverFrame,"SetupClassNameplateBars", UpdateClassFrame)
